var crypto = require('crypto');
var MongoDB = require('mongodb').Db;
var Server = require('mongodb').Server;
var moment = require('moment');

/*
 ESTABLISH DATABASE CONNECTION (数据连接）
 */

var dbName = process.env.DB_NAME || 'xjtuMEDICAL';
var dbHost = process.env.DB_HOST || 'localhost';
var dbPort = process.env.DB_PORT || 27017;

//数据实例
var db = new MongoDB(dbName, new Server(dbHost, dbPort, {auto_reconnect: true}), {w: 1});
db.open(function (e, d) {
    if (e) {
        console.log(e);
    } else {
        if (process.env.NODE_ENV == 'live') {
            db.authenticate(process.env.DB_USER, process.env.DB_PASS, function (e, res) {
                if (e) {
                    console.log('mongo :: error: not authenticated', e);
                }
                else {
                    console.log('mongo :: authenticated and connected to database :: "' + dbName + '"');
                }
            });
        } else {
            console.log('mongo :: connected to database :: "' + dbName + '"');
        }
    }
});

//用户表
var accounts = db.collection('accounts');


/* login validation methods, 使用cookie */
exports.autoLogin = function (nameEmail, pass, callback) {
    accounts.findOne({
        $or: [
            {'name': nameEmail},
            {'email': nameEmail}
        ]
    }, function (err, result) {
        if (result) {
            result.pass == pass ? callback(result) : callback(null);
        } else {
            callback(null);
        }
    });
};

//手动登录
exports.manualLogin = function (nameEmail, pass, callback) {
    returnMsg = {};
    accounts.findOne({
        $or: [
            {'name': nameEmail},
            {'email': nameEmail}
        ]
    }, function (e, o) {
        if (o == null) {
            returnMsg['code'] = 0;
            returnMsg['msg'] = '用户名/邮箱不存在';
            callback(returnMsg);
        } else {
            validatePassword(pass, o.pass, function (err, res) {
                if (res) {
                    returnMsg['code'] = 1;
                    returnMsg['msg'] = '登录成功';
                    returnMsg['user'] = o;
                    callback(returnMsg);
                } else {
                    returnMsg['code'] = 0;
                    returnMsg['msg'] = '密码错误';
                    callback(returnMsg);
                }
            });
        }
    });
};

//注册新用户
/* record insertion, update & deletion methods */
exports.addNewAccount = function (newData, callback) {
    returnMsg = {};
    accounts.findOne({email: newData.email}, function (e, o) { //验证邮箱
        if (o) {
            returnMsg['code'] = 0;
            returnMsg['msg'] = '该邮箱已注册';
            callback(returnMsg);
        } else {
            accounts.findOne({email: newData.name}, function (e, o) { //验证用户名
                if(o){
                    returnMsg['code'] = 0;
                    returnMsg['msg'] = '用户名已存在';
                    callback(returnMsg);
                }else{
                    saltAndHash(newData.pass, function (hash) {
                        newData.pass = hash; //密码加密
                        //注册时间
                        newData.date = moment().unix(); //注册时间毫秒值
                        accounts.insert(newData, {safe: true}, function (e, o) {
                            if(!e){
                                returnMsg['code'] = 1;
                                returnMsg['msg'] = '注册成功';
                                callback(returnMsg);
                            }else{
                                returnMsg['code'] = 0;
                                returnMsg['msg'] = '注册失败';
                                callback(returnMsg);
                            }
                        });
                    });
                }
            });

        }
    });
};


//更新用户信息
exports.updateAccount = function (newData, callback) {
    accounts.findOne({_id: getObjectId(newData.id)}, function (e, o) {
        o.name = newData.name;
        o.email = newData.email;
        o.country = newData.country;
        if (newData.pass == '') {
            accounts.save(o, {safe: true}, function (e) {
                if (e) callback(e);
                else callback(null, o);
            });
        } else {
            saltAndHash(newData.pass, function (hash) {
                o.pass = hash;
                accounts.save(o, {safe: true}, function (e) {
                    if (e) callback(e);
                    else callback(null, o);
                });
            });
        }
    });
};

exports.updatePassword = function (email, newPass, callback) {
    accounts.findOne({email: email}, function (e, o) {
        if (e) {
            callback(e, null);
        } else {
            saltAndHash(newPass, function (hash) {
                o.pass = hash;
                accounts.save(o, {safe: true}, callback);
            });
        }
    });
};

/* account lookup methods */

exports.deleteAccount = function (id, callback) {
    accounts.remove({_id: getObjectId(id)}, callback);
};

exports.getAccountByEmail = function (email, callback) {
    accounts.findOne({email: email}, function (e, o) {
        callback(o);
    });
};

exports.validateResetLink = function (email, passHash, callback) {
    accounts.find({$and: [{email: email, pass: passHash}]}, function (e, o) {
        callback(o ? 'ok' : null);
    });
};

exports.getAllRecords = function (callback) {
    accounts.find().toArray(
        function (e, res) {
            if (e)
                callback(e);
            else
                callback(null, res);
        });
};

exports.delAllRecords = function (callback) {
    accounts.remove({}, callback); // reset accounts collection for testing //
};

/* private encryption & validation methods */

var generateSalt = function () {
    var set = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
    var salt = '';
    for (var i = 0; i < 10; i++) {
        var p = Math.floor(Math.random() * set.length);
        salt += set[p];
    }
    return salt;
};

var md5 = function (str) {
    return crypto.createHash('md5').update(str).digest('hex');
};

var saltAndHash = function (pass, callback) {
    var salt = generateSalt();
    callback(salt + md5(pass + salt));
};


var validatePassword = function (plainPass, hashedPass, callback) {
    var salt = hashedPass.substr(0, 10);
    var validHash = salt + md5(plainPass + salt);
    callback(null, hashedPass === validHash);
};


var getObjectId = function (id) {
    return new require('mongodb').ObjectID(id);
};

var findById = function (id, callback) {
    accounts.findOne({_id: getObjectId(id)},
        function (e, res) {
            if (e)
                callback(e);
            else
                callback(null, res);
        });
};

var findByMultipleFields = function (a, callback) {
// this takes an array of name/val pairs to search against {fieldName : 'value'} //
    accounts.find({$or: a}).toArray(
        function (e, results) {
            if (e)
                callback(e);
            else
                callback(null, results);
        });
};
